package com.google.zxing.client.ohos.camera;


import com.asher.zxingmodule.BaseAbility;
import com.google.zxing.PlanarYUVLuminanceSource;
import ohos.agp.graphics.Surface;
import ohos.agp.utils.Point;
import ohos.agp.utils.Rect;
import ohos.agp.window.service.Window;
import ohos.agp.window.service.WindowManager;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.camera.CameraKit;
import ohos.media.camera.device.Camera;
import ohos.media.camera.device.CameraConfig;
import ohos.media.camera.device.CameraDeviceCallback;
import ohos.media.camera.device.FrameConfig;
import ohos.media.image.ImageReceiver;
import ohos.media.image.common.ImageFormat;
import ohos.media.image.common.Size;

import java.util.List;

import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PREVIEW;

public class CameraManager {
    private static final int MIN_FRAME_WIDTH = 240;
    private static final int MIN_FRAME_HEIGHT = 240;
    private static final int MAX_FRAME_WIDTH = 1200; // = 5/8 * 1920
    private static final int MAX_FRAME_HEIGHT = 675; // = 5/8 * 1080

    final int CAM_MODULE = 0x00201;
    final HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, CAM_MODULE, "cameraManager");
    private Context mContext= null;
    private CameraKit mCameraKit;
    private String cameraId = null;
    private Camera mCamera;
    private FrameConfig previewFrameConfig;

    private ImageReceiverCallback receiverCallback;

    private DecodeHandler decodeHandler;
    private EventHandler cameraHandler = new EventHandler(EventRunner.create("camera"));

    private boolean triggering = false;
    private Rect framRect;
    private Size pictureSize;
    private int windowWidth;
    private int windowHeight;
    public CameraManager(Context context,BaseAbility baseAbility){
        this.mContext = context;
        mCameraKit = CameraKit.getInstance(mContext);
        decodeHandler = new DecodeHandler(EventRunner.create("decode"),baseAbility);
    }

    public void setCameraId(String cameraId){
        this.cameraId = cameraId;
    }

    public String getCameraId(){
        if (cameraId == null){
            String[] cameraIds = mCameraKit.getCameraIds();
            if (cameraIds != null && cameraIds.length>0){
                cameraId = cameraIds[0];
            }
        }

        return cameraId;
    }

    public void creatCamera(CameraStateImpl cameraStateCallback) {
        mCameraKit.createCamera(getCameraId(),cameraStateCallback,cameraHandler);
        mCameraKit.registerCameraDeviceCallback(new CameraDeviceCallback() {
            @Override
            public void onCameraStatus(String cameraId, int status) {
                super.onCameraStatus(cameraId, status);
            }

            @Override
            public void onPhysicalCameraStatus(String cameraId, int status) {
                super.onPhysicalCameraStatus(cameraId, status);
            }

            @Override
            public void onFlashlightStatus(String cameraId, int status) {
                super.onFlashlightStatus(cameraId, status);
            }
        }, cameraHandler);
    }


    public void tiggerLoopingCapture(Camera camera, Surface surface,int width,int height) {

        initFrameRect(width,height);
        if (camera != null){
            this.mCamera = camera;
        }
        if (mCamera == null){
            HiLog.info(label,"no Camera for triggerLoopingCapture");
            return;
        }
        CameraConfig.Builder cameraConfigBuilder = mCamera.getCameraConfigBuilder();
        if (cameraConfigBuilder == null) {
            return;
        }
        // 获取预览配置模板
        FrameConfig.Builder frameConfigBuilder = mCamera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW);
        // 配置预览Surface
        frameConfigBuilder.addSurface(surface);
        previewFrameConfig = frameConfigBuilder.build();
        // 配置预览的Surface
        cameraConfigBuilder.addSurface(surface);

        List<Size> pictureSizes = mCameraKit.getCameraAbility(getCameraId()).getSupportedSizes(ImageFormat.JPEG); // 获取拍照支持分辨率列表
        pictureSize = CameraConfigurationUtil.getBestSize(pictureSizes,width,height);
        ImageReceiver imageReceiver = ImageReceiver.create(Math.max(pictureSize.width, pictureSize.height),Math.min(pictureSize.width, pictureSize.height), ImageFormat.JPEG, 5); // 创建ImageReceiver对象，注意creat函数中宽度要大于高度；5为最大支持的图像数，请根据实际设置。
        receiverCallback = new ImageReceiverCallback();
        startCallbackHandler();
        imageReceiver.setImageArrivalListener(receiverCallback);
        // 配置拍照的Surface
        cameraConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
        // 配置帧结果的回调
        cameraConfigBuilder.setFrameStateCallback(new FrameStateCallbackImpl(), cameraHandler);
        try {
            // 相机设备配置
            mCamera.configure(cameraConfigBuilder.build());
            // 启动循环帧捕获
            int triggerId = mCamera.triggerLoopingCapture(previewFrameConfig);
            triggering = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void startCallbackHandler() {
        if (receiverCallback != null){
            receiverCallback.setHandler(decodeHandler);
        }
    }

    public void stopTrigger(){
        if (mCamera != null && triggering){
            mCamera.stopLoopingCapture();
            triggering = false;
        }
    }

    public void startLoopTrigger(){
        if (mCamera != null && previewFrameConfig != null && !triggering){
            mCamera.triggerLoopingCapture(previewFrameConfig);
            triggering = true;
        }
    }

    public void stop(){
        if (mCamera != null){
            mCamera.flushCaptures();
        }
    }

    private void initFrameRect(int w, int h) {
        windowHeight = h;
        windowWidth = w;
        int width = findDesiredDimensionInRange(w, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
        int height = findDesiredDimensionInRange(h, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
        int leftOffset = (w - width) / 2;
        int topOffset = (h - height) / 2;
        framRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);

    }

    public Rect getFramingRect(){
        if (framRect == null){
            WindowManager windowManager = WindowManager.getInstance();
            Rect rect = windowManager.getTopWindow().get().getBoundRect();
            initFrameRect(rect.right,rect.bottom);
        }
        return framRect;
    }

    public Rect getFramingRectInPreview(){
        Rect framingRect = getFramingRect();
        if (framingRect == null) {
            return null;
        }
        Rect rect = new Rect(framingRect.left,framingRect.top,framingRect.right,framingRect.bottom);
        if (windowWidth <= 0|| pictureSize == null) {
            // Called early, before init even finished
            return null;
        }
        rect.left = rect.left * windowWidth/ pictureSize.width;
        rect.right = rect.right * windowWidth/ pictureSize.width;
        rect.top = rect.top * windowHeight/ pictureSize.height;
        rect.bottom = rect.bottom * windowHeight/ pictureSize.height;
        return rect;
    }


    private static int findDesiredDimensionInRange(int resolution, int hardMin, int hardMax) {
        int dim = 5 * resolution / 8; // Target 5/8 of each dimension
        if (dim < hardMin) {
            return hardMin;
        }
        return Math.min(dim, hardMax);
    }

    public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
        Rect rect = getFramingRectInPreview();
        if (rect == null) {
            rect = getFramingRect();
        }
        if (rect == null) {
            return null;
        }
        // Go ahead and assume it's YUV rather than die.
        return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
                rect.right-rect.left, rect.bottom - rect.top, false);
    }



}
